#include "pch.h"


float2 Robot::GetCorePosition()
{
	return m_CorePosition;
}

void Robot::SetCorePosition(const float2& cp)
{
	m_CorePosition = cp;
}

Robot::Robot():m_CurentCommand(Command_Idle)
			  ,m_Inverse(false)
			  ,uid(0)
{
	uid = GenerateKey();
}

Robot::~Robot()
{
	m_PartCreateVec.clear();
	m_RobotPartMap.clear();

}

void Robot::RemovePart(uint part_id)
{
	auto itor = m_RobotPartMap.find(part_id);
	if(itor != m_RobotPartMap.end())
	{
		m_RobotPartMap.erase(itor);
	}

	if(part_id == m_RobotCore->uid)
	{
		m_RobotCore = nullptr;
	}
}

void Robot::SetActive(bool flag)
{
	auto itor = m_RobotPartMap.begin();
	for (;itor != m_RobotPartMap.end(); itor++)
	{
		itor->second->SetActive(flag);
	}
}

void Robot::Reset()
{
	m_RobotPartMap.clear();

	m_RobotCore = nullptr;
	
	CreateParts();
}

void Robot::Clear()
{
	m_RobotPartMap.clear();

	m_RobotCore = nullptr;

	m_PartCreateVec.clear();

	m_JointCreateVec.clear();
}

void Robot::Inverse()
{
	m_Inverse = !m_Inverse;
}

void Robot::SetCommand(RobotCommandState c)
{
	m_CurentCommand = c;
	auto itor = m_RobotPartMap.begin();
	for (;itor != m_RobotPartMap.end(); itor++)
	{
		itor->second->UpdateCommand(c);
	}
}

void Robot::OnUpdate(float frameTime)
{
	auto itor = m_RobotPartMap.begin();
	for (;itor != m_RobotPartMap.end(); itor++)
	{
		itor->second->OnUpdateAction(frameTime);
		itor->second->OnUpdate(frameTime);
	}
	if(m_RobotCore)
		m_CorePosition = m_RobotCore->GetPosition();
}

void Robot::OnPreRender()
{
	auto itor = m_RobotPartMap.begin();
	for (;itor != m_RobotPartMap.end(); itor++)
	{
		itor->second->OnPreRender();
	}
}

void Robot::Initialize()
{
	auto itor = m_RobotPartMap.begin();
	for (;itor != m_RobotPartMap.end(); itor++)
	{
		if(itor->second->GetPartType() == Part_TypeCore)
		{
			m_RobotCore = itor->second;
		}
	}
}

bool Robot::LoadParts(tinyxml2::XMLElement * robot_node, bool reverse)
{
	for (tinyxml2::XMLElement *part = robot_node->FirstChildElement(XML_PART); part != NULL; part = part->NextSiblingElement(XML_PART))
	{
		
		uint object_type = 0;

		if(part->QueryUnsignedAttribute(XML_OBJECT_TYPE, &object_type) != tinyxml2::XML_NO_ERROR)
			return false;

		if(object_type == 1)
		{
			PartCreateInfo info;

			if(part->QueryUnsignedAttribute(XML_PART_ID, &info.uid) != tinyxml2::XML_NO_ERROR)
				return false;
			if(part->QueryFloatAttribute(XML_PART_POSITION_X, &info.local_position.x) != tinyxml2::XML_NO_ERROR)
				return false;
			if(part->QueryFloatAttribute(XML_PART_POSITION_Y, &info.local_position.y) != tinyxml2::XML_NO_ERROR)
				return false;
			if(part->QueryFloatAttribute(XML_PART_ROTATION, &info.local_rotation) != tinyxml2::XML_NO_ERROR)
				return false;
			if(part->QueryIntAttribute(XML_PART_TYPE, &info.part_type) != tinyxml2::XML_NO_ERROR)
				return false;

			info.reverse = reverse;

			m_PartCreateVec.push_back(info);
		}
		else if(object_type == 2)
		{
			JointCreateInfo info;

			if(part->QueryUnsignedAttribute(XML_JOINT_ID_A, &info.partA_uid) != tinyxml2::XML_NO_ERROR)
				return false;
			if(part->QueryUnsignedAttribute(XML_JOINT_ID_B, &info.partB_uid) != tinyxml2::XML_NO_ERROR)
				return false;

			m_JointCreateVec.push_back(info);
		}
		else
		{
			return false;
		}

		
		
	}
	return true;
}


void Robot::CreateJoints()
{
	b2RevoluteJointDef jd;
	jd.upperAngle = 1.8f;
	jd.enableLimit = true;
	jd.motorSpeed = 1.f;
	jd.enableMotor = true;

	b2World* world_ref = Box2DManager::Instance()->GetWorld();

	for (uint i = 0; i < m_JointCreateVec.size(); i++)
	{
		const JointCreateInfo& info = m_JointCreateVec[i];
		auto itorA = m_RobotPartMap.find(info.partA_uid);
		if(itorA == m_RobotPartMap.end())
			continue;

		auto itorB = m_RobotPartMap.find(info.partB_uid);
		if(itorB == m_RobotPartMap.end())
			continue;

		const b2BodySmart& pA = itorA->second->GetBodySmart();
		const b2BodySmart& pB = itorB->second->GetBodySmart();

		Box2DManager::Instance()->CreateJoint(pA, pB,jd);
	}
}

void Robot::AddJointsDef(const JointCreateInfo& info)
{
	m_JointCreateVec.push_back(info);
}

void Robot::AddPartDef(const PartCreateInfo& info)
{
	m_PartCreateVec.push_back(info);
}

void Robot::CreateParts()
{
	for (uint i = 0; i < m_PartCreateVec.size(); i++)
	{
		PartCreateInfo& info = m_PartCreateVec[i];
		info.core_position = m_CorePosition;


		RobotPartBase* robot_part= NULL;
		switch(info.part_type)
		{
		case Part_TypeCore:
			{
				info.size.x = 8.f;
				info.size.y = 4.f;
				robot_part = new RobotPartBody();
				robot_part->uid = info.uid;
				robot_part->SetOwnerId(uid);
				robot_part->Create(info);
				robot_part->SetPartType(Part_TypeCore);
			}
			break;
		case Part_TypeBody:
			{
				info.size.x = 6.f;
				info.size.y = 1.f;
				robot_part = new RobotPartBody();
				robot_part->uid = info.uid;
				robot_part->SetOwnerId(uid);
				robot_part->Create(info);
				robot_part->SetPartType(Part_TypeBody);
			}
			break;

		}

		if(robot_part)
		{
			std::shared_ptr<RobotPartBase> s(robot_part);
			m_RobotPartMap.insert(std::make_pair(s->uid, s));
			robot_part->Initialize();
		}
	}
}

void Robot::SaveAttribute(tinyxml2::XMLDocument& doc, tinyxml2::XMLNode* robot_node)
{
	{
		auto itor = m_PartCreateVec.begin();
		for(;itor != m_PartCreateVec.end();itor ++)
		{
			const PartCreateInfo& info = *itor;
			tinyxml2::XMLElement* part = doc.NewElement(XML_PART);
			robot_node->InsertEndChild(part);
			part->SetAttribute(XML_OBJECT_TYPE, 1);
			part->SetAttribute(XML_PART_ID, info.uid);
			part->SetAttribute(XML_PART_TYPE, info.part_type);
			part->SetAttribute(XML_PART_POSITION_X, info.local_position.x);
			part->SetAttribute(XML_PART_POSITION_Y, info.local_position.y);
			part->SetAttribute(XML_PART_ROTATION, info.local_rotation);
		}
	}

	{
		auto itor = m_JointCreateVec.begin();
		for(;itor != m_JointCreateVec.end();itor ++)
		{
			const JointCreateInfo& info = *itor;
			tinyxml2::XMLElement* part = doc.NewElement(XML_PART);
			robot_node->InsertEndChild(part);
			part->SetAttribute(XML_OBJECT_TYPE, 2);
			part->SetAttribute(XML_JOINT_ID_A, info.partA_uid);
			part->SetAttribute(XML_JOINT_ID_B, info.partB_uid);
		}
	}
}